/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_API_REFLECTION_BASIC_OPERATION_HPP
#define	_CUBEFS_API_REFLECTION_BASIC_OPERATION_HPP

#include <cubefs/core/api/reflection/operation.hpp>

#define CUBEFS_SOURCE "cubefs/core/api/reflection/basic_operation.hpp:" CUBEFS_AT

namespace cubefs    {
namespace api       {


//template <typename Pattern, typename Functor = Pattern> class BasicOperation;
//template <typename Pattern, typename Functor = Pattern> class BasicStaticOperation;


template <typename Functor>
class BasicStaticOperation<Typed* (*)(), Functor>: public AbstractOperationImpl<0> {
    typedef AbstractOperationImpl<0> Base;

    Functor functor_;

public:
    BasicStaticOperation(Type *owner, Type* return_type, const std::string name, Functor functor):
        Base(owner, return_type, name, true),
        functor_(functor) {}

    virtual Typed* invokeTyped(Typed* target, StaticListOfTyped* arguments) const {
        return Base::CheckReturnValue((*functor_)());
    }
};

template <typename Target, typename Functor>
class BasicOperation<Typed* (Target::*)(), Functor>: public AbstractOperationImpl<0> {
    typedef AbstractOperationImpl<0> Base;

    Functor functor_;

public:
    BasicOperation(Type *owner, Type* return_type, const std::string name, Functor functor):
        Base(owner, return_type, name), functor_(functor) {}

    virtual Typed *invoke(Typed* target, StaticListOfTyped* arguments) const
    {
        Base::CheckTargetValue(target);
        Target* tgt = static_cast<Target*>(target);
        return Base::CheckReturnValue((tgt->*functor_)());
    }
};

template <typename T1, typename Functor>
class BasicStaticOperation<Typed* (*)(T1), Functor>: public AbstractOperationImpl<1> {
    typedef AbstractOperationImpl<1> Base;

    Functor functor_;

public:

    BasicStaticOperation(Type *owner, const std::string &name,
                const std::string &p0_name,
                Functor functor):
         Base(owner, NULL, name, true),
         functor_(functor)
    {
    	Type* p0_type = TypeFactory<T1>::type();
    	Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
    }

    BasicStaticOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            Functor functor
    ):
        Base(owner, return_type, name, true),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
    }

    virtual Typed* invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckArgumentTypes(arguments);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));

        return Base::CheckReturnValue((*functor_)(t1));
    }
};

template <typename Target, typename T1, typename Functor>
class BasicOperation<Typed* (Target::*)(T1), Functor>: public AbstractOperationImpl<1> {
    typedef AbstractOperationImpl<1> Base;

    Functor functor_;

public:
    BasicOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            Functor functor
    ):
        Base(owner, return_type, name, false),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
    }

    BasicOperation(Type *owner, const std::string &name,
                const std::string &p0_name,
                Functor functor
    ):
    	Base(owner, NULL, name, false),
    	functor_(functor)
    {
    	Type* p0_type = TypeFactory<T1>::type();
    	Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
    }

    virtual Typed *invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckTargetValue(target);
        Base::CheckArgumentTypes(arguments);

        Target* tgt = static_cast<Target*>(target);
        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));

        return Base::CheckReturnValue((tgt->*functor_)(t1));
    }
};





template <typename T1, typename T2, typename Functor>
class BasicStaticOperation<Typed* (*)(T1, T2), Functor>: public AbstractOperationImpl<2> {
    typedef AbstractOperationImpl<2> Base;

    Functor functor_;

public:
    BasicStaticOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            Functor functor
    ):
        Base(owner, return_type, name, true),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
    }

    virtual Typed* invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckArgumentTypes(arguments);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));

        return Base::CheckReturnValue((*functor_)(t1, t2));
    }
};

template <typename Target, typename T1, typename T2, typename Functor>
class BasicOperation<Typed* (Target::*)(T1, T2), Functor>: public AbstractOperationImpl<2> {
    typedef AbstractOperationImpl<2> Base;

    Functor functor_;

public:
    BasicOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            Functor functor
    ):
        Base(owner, return_type, name, false),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
    }

    virtual Typed *invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckTargetValue(target);
        Base::CheckArgumentTypes(arguments);

        Target* tgt = static_cast<Target*>(target);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));

        return Base::CheckReturnValue((tgt->*functor_)(t1, t2));
    }
};





template <typename T1, typename T2, typename T3, typename Functor>
class BasicStaticOperation<Typed* (*)(T1, T2, T3), Functor>: public AbstractOperationImpl<3> {
    typedef AbstractOperationImpl<3> Base;

    Functor functor_;

public:
    BasicStaticOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            const std::string &p2_name,
            Functor functor
    ):
        Base(owner, return_type, name, true),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();
        Type* p2_type = TypeFactory<T3>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
        Base::AddArgumentType(new ArgumentImpl(p2_name, p2_type));
    }

    virtual Typed* invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckArgumentTypes(arguments);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));
        T3 t3 = ParameterTypeHelper<T3>::convert(arguments->Get(2));

        return Base::CheckReturnValue((*functor_)(t1, t2, t3));
    }
};

template <typename Target, typename T1, typename T2, typename T3, typename Functor>
class BasicOperation<Typed* (Target::*)(T1, T2, T3), Functor>: public AbstractOperationImpl<3> {
    typedef AbstractOperationImpl<3> Base;

    Functor functor_;

public:
    BasicOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            const std::string &p2_name,
            Functor functor
    ):
        Base(owner, return_type, name, false),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();
        Type* p2_type = TypeFactory<T3>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
        Base::AddArgumentType(new ArgumentImpl(p2_name, p2_type));
    }

    virtual Typed *invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckTargetValue(target);
        Base::CheckArgumentTypes(arguments);

        Target* tgt = static_cast<Target*>(target);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));
        T3 t3 = ParameterTypeHelper<T3>::convert(arguments->Get(2));

        return Base::CheckReturnValue((tgt->*functor_)(t1, t2, t3));
    }
};





template <typename T1, typename T2, typename T3, typename T4, typename Functor>
class BasicStaticOperation<Typed* (*)(T1, T2, T3, T4), Functor>: public AbstractOperationImpl<4> {
    typedef AbstractOperationImpl<4> Base;

    Functor functor_;

public:
    BasicStaticOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            const std::string &p2_name,
            const std::string &p3_name,
            Functor functor
    ):
        Base(owner, return_type, name, true),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();
        Type* p2_type = TypeFactory<T3>::type();
        Type* p3_type = TypeFactory<T3>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
        Base::AddArgumentType(new ArgumentImpl(p2_name, p2_type));
        Base::AddArgumentType(new ArgumentImpl(p3_name, p3_type));
    }

    virtual Typed* invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckArgumentTypes(arguments);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));
        T3 t3 = ParameterTypeHelper<T3>::convert(arguments->Get(2));
        T4 t4 = ParameterTypeHelper<T4>::convert(arguments->Get(3));

        return Base::CheckReturnValue((*functor_)(t1, t2, t3, t4));
    }
};

template <typename Target, typename T1, typename T2, typename T3, typename T4, typename Functor>
class BasicOperation<Typed* (Target::*)(T1, T2, T3, T4), Functor>: public AbstractOperationImpl<4> {
    typedef AbstractOperationImpl<4> Base;

    Functor functor_;

public:
    BasicOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            const std::string &p2_name,
            const std::string &p3_name,
            Functor functor
    ):
        Base(owner, name, return_type, false),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();
        Type* p2_type = TypeFactory<T3>::type();
        Type* p3_type = TypeFactory<T4>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
        Base::AddArgumentType(new ArgumentImpl(p2_name, p2_type));
        Base::AddArgumentType(new ArgumentImpl(p3_name, p3_type));
    }

    virtual Typed *invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckTargetValue(target);
        Base::CheckArgumentTypes(arguments);

        Target* tgt = static_cast<Target*>(target);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));
        T3 t3 = ParameterTypeHelper<T3>::convert(arguments->Get(2));
        T3 t4 = ParameterTypeHelper<T4>::convert(arguments->Get(3));

        return Base::CheckReturnValue((tgt->*functor_)(t1, t2, t3, t4));
    }
};





template <typename Target, typename T1, typename T2, typename T3, typename T4, typename T5, typename Functor>
class BasicOperation<Typed* (Target::*)(T1, T2, T3, T4, T5), Functor>: public AbstractOperationImpl<5> {
    typedef AbstractOperationImpl<5> Base;

    Functor functor_;

public:
    BasicOperation(Type *owner, Type* return_type, const std::string &name,
            const std::string &p0_name,
            const std::string &p1_name,
            const std::string &p2_name,
            const std::string &p3_name,
            const std::string &p4_name,
            Functor functor
    ):
        Base(owner, name, return_type, false),
        functor_(functor)
    {
        Type* p0_type = TypeFactory<T1>::type();
        Type* p1_type = TypeFactory<T2>::type();
        Type* p2_type = TypeFactory<T3>::type();
        Type* p3_type = TypeFactory<T4>::type();
        Type* p4_type = TypeFactory<T5>::type();

        Base::AddArgumentType(new ArgumentImpl(p0_name, p0_type));
        Base::AddArgumentType(new ArgumentImpl(p1_name, p1_type));
        Base::AddArgumentType(new ArgumentImpl(p2_name, p2_type));
        Base::AddArgumentType(new ArgumentImpl(p3_name, p3_type));
        Base::AddArgumentType(new ArgumentImpl(p4_name, p4_type));
    }

    virtual Typed *invoke(Typed* target, StaticListOfTyped* arguments) const {
        Base::CheckTargetValue(target);
        Base::CheckArgumentTypes(arguments);

        Target* tgt = static_cast<Target*>(target);

        T1 t1 = ParameterTypeHelper<T1>::convert(arguments->Get(0));
        T2 t2 = ParameterTypeHelper<T2>::convert(arguments->Get(1));
        T3 t3 = ParameterTypeHelper<T3>::convert(arguments->Get(2));
        T4 t4 = ParameterTypeHelper<T4>::convert(arguments->Get(3));
        T5 t5 = ParameterTypeHelper<T5>::convert(arguments->Get(4));

        return Base::CheckReturnValue((tgt->*functor_)(t1, t2, t3, t4, t5));
    }
};


template <typename Interface>
void TypedImplT<Interface>::InitOperations()			 {
	AbstractType *type = static_cast<AbstractType*>(type_);

	type->AddOperation(new BasicOperation<bool (Me::*)(const Type*), bool (Me::*)(const Type*) const>(type, "IsInstance", "type", &Me::IsInstance));
	type->AddOperation(new BasicOperation<bool (Me::*)(), bool (Me::*)() const>(type, "managed", &Me::managed));
	type->AddOperation(new BasicOperation<Typed* (Me::*)(), Type* (Me::*)() const>(type, Type::MyType(), "type", &Me::type));
}


template <typename Interface>
void TypeImplT<Interface>::InitOperations() {
	Me *type = static_cast<Me*>(type_);

	type->AddOperation(new BasicOperation<StringRef (Me::*)(), StringRef (Me::*)() const>(type, "name", &Me::name));
	type->AddOperation(new BasicOperation<Int (Me::*)(), Int (Me::*)() const>(type, "GetOperationsCount", &Me::GetOperationsCount));

	type->AddOperation(new BasicOperation<Typed* (Me::*)(Int), Operation* (Me::*)(Int) const>(type, Operation::MyType(), "GetOperation", "index", &Me::GetOperation));

	typedef TypedList<Type*> TypeList;

	type->AddOperation(new BasicOperation<Typed* (Me::*)(StringRef, TypeList*), Operation* (Me::*)(StringRef, TypeList*) const>(type, Operation::MyType(), "FindOperation", "name", "parameters", &Me::FindOperation));

	type->AddOperation(new BasicOperation<bool (Me::*)(const Type*), bool (Me::*)(const Type*) const>(type, "IsSameOrSubclass", "type", &Me::IsSameOrSubclass));

	type->AddOperation(new BasicOperation<Typed* (Me::*)(), Type* (Me::*)() const>(type, Me::MyType(), "type", &Me::type));
}

template <typename Interface>
void OperationImplT<Interface>::InitOperations() {
   	AbstractType *type = static_cast<AbstractType*>(type_);

   	type->AddOperation(new BasicOperation<StringRef (Me::*)(), StringRef (Me::*)() const>(type, "name", &Me::name));
   	type->AddOperation(new BasicOperation<Typed* (Me::*)(), Type* (Me::*)() const>(type, Type::MyType(), "GetReturnType", &Me::GetReturnType));
   	type->AddOperation(new BasicOperation<Int (Me::*)(), Int (Me::*)() const>(type, "GetArgumentsCount", &Me::GetArgumentsCount));

//   	type->AddOperation(new InvokeOp(type));
}


}
}

#undef CUBEFS_SOURCE

#endif //_CUBEFS_API_REFLECTION_ABSTRACT_OPERATION_HPP
